#ifndef _POLLER_H_
#define _POLLER_H_

//define the poller interface,hide implementation
//of defferent poller. eg. select, epoll, kqueue etc.
//
#include <sys/select.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <vector>

typedef enum _PollFlag {
	POLLER_RD     = 0x1,
	POLLER_WR     = 0x2,
	POLLER_RDWR   = 0x3,
	POLLER_MASK   = 0x3,
}PollFlag;

class Poller {
	public:	
		//poller interface 

		//@fd: fd to watch
		//@flag: watch flag
		virtual bool WatchFd(int fd, PollFlag flag) = 0;

		//@fd: fd to remove from watch
		//@flag: unwatch flag
		virtual bool UnwatchFd(int fd, PollFlag flag) = 0;

		//@fd: fd to test if it watched
		//@flag: flag to test
		virtual bool IsWatched(int fd, PollFlag flag) = 0;

		//@rv: result set of read events
		//@wv: result set of write events
		//@timeout: time to wait in "ms", default: wait forever
		virtual void WaitEvents(std::vector<int> *rv, std::vector<int> *wv, int timeout = -1) = 0;

		virtual ~Poller() { }
};

class SelectIO : public Poller {
	public:
		SelectIO();
		~SelectIO();
	public:
		virtual bool WatchFd(int fd, PollFlag flag);
		virtual bool UnwatchFd(int fd, PollFlag flag);
		virtual bool IsWatched(int fd, PollFlag flag);
		virtual void WaitEvents(std::vector<int> *rv, std::vector<int> *wv, int timeout = -1);

	private:
		//mutext protect rset and wset.
		pthread_mutex_t _m;
		fd_set _rset;
		fd_set _wset;
		int _highfd;
};

class EpollIO : public Poller {
	public:
		EpollIO(int maxfd);
		~EpollIO();

	public:
		virtual bool WatchFd(int fd, PollFlag flag);
		virtual bool UnwatchFd(int fd, PollFlag flag);
		virtual bool IsWatched(int fd, PollFlag flag);
		virtual void WaitEvents(std::vector<int> *rv, std::vector<int> *wv, int timeout = -1);
		
	private:
		int _efd;
		int _maxfd;
		struct epoll_event *_evts;
		int *_status;
};
#endif //poller.h
